package com.mall.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import com.alipay.api.AlipayApiException;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.google.common.util.concurrent.AtomicDouble;
import com.mall.DTO.WaresDTO;
import com.mall.common.Constant;
import com.mall.exception.NoAddressException;
import com.mall.mapper.*;
import com.mall.pojo.*;
import com.mall.service.IOrderService;
import com.mall.service.IWaresService;
import com.mall.utils.AlipayUtil;
import com.mall.utils.ListByteConverterUtil;
import com.mall.utils.R;
import com.mall.utils.ThreadLocalUtils;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author xiao-chen
 * @since 2023-04-20
 */
@Slf4j
@Service
public class WaresServiceImpl extends ServiceImpl<WaresMapper, Wares> implements IWaresService {
    @Resource
    private WaresMapper wareMapper;
    @Resource
    private CategoryMapper categoryMapper;
    @Resource
    private RedisTemplate<String, Object> redisTemplate;
    @Resource
    private DefaultRedisScript<Long> decrScript;
    @Resource
    private IOrderService orderService;
    @Resource
    private RabbitTemplate rabbitTemplate;
    @Resource
    private OrderMapper orderMapper;
    @Resource
    private AddressMapper addressMapper;
    @Resource
    private OrderDetailMapper orderDetailMapper;
    @Resource
    private AlipayUtil aliPayUtil;
    @Resource
    private ThreadLocalUtils threadLocalUtils;

    @Override
    public Page<WaresDTO> getWaresWithclassName(Integer page, Integer pageSize, String wareName) {
        Page<Wares> waresPage = new Page<>(page, pageSize);
        LambdaQueryWrapper<Wares> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.like(StringUtils.isNotBlank(wareName), Wares::getName, wareName);
        wareMapper.selectPage(waresPage, queryWrapper);
        Page<WaresDTO> waresDtoPage = new Page<>();
        //将waresPage里面的数据赋值给waresDtoPage忽略掉records里面的数据
        BeanUtils.copyProperties(waresPage, waresDtoPage, "records");
        List<WaresDTO> waresDTOList = waresPage.getRecords().stream().map(ware -> {
            WaresDTO waresDTO = new WaresDTO();
            BeanUtils.copyProperties(ware, waresDTO);
            waresDTO.setClassName(categoryMapper.getCategoryNameByWareId(ware.getId()));
            return waresDTO;
        }).collect(Collectors.toList());
        waresDtoPage.setRecords(waresDTOList);
        return waresDtoPage;
    }


    @Override
    public boolean updateWaresByIdWithclassName(WaresDTO ware) {
        LambdaQueryWrapper<Category> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Category::getName, ware.getClassName());
        Category one = categoryMapper.selectOne(wrapper);
        if (ObjectUtils.isNotEmpty(one)) {
            ware.setCategoryId(one.getId());
        }
        int i = wareMapper.updateById(ware);
        return i != 0;
    }


    @Override
    public boolean saveWaresWithclassName(WaresDTO ware) {
        LambdaQueryWrapper<Category> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Category::getName, ware.getClassName());
        Category one = categoryMapper.selectOne(wrapper);
        ware.setCategoryId(one.getId());
        int i = wareMapper.insert(ware);

        return i != 0;
    }

    public List<Wares> getWaresByCategoryId(Long categoryId) {
        LambdaQueryWrapper<Wares> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Wares::getCategoryId, categoryId);
        return wareMapper.selectList(wrapper);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String buyWareAndsaveOrderDetail(List<WaresDTO> list) throws Exception {
        AtomicDouble amount = new AtomicDouble(0.0);
        ValueOperations<String, Object> operations = redisTemplate.opsForValue();
        Order order = new Order();
        //计算订单总价格
        list.forEach(ware -> {
            BigDecimal price = BigDecimal.valueOf((Double) operations.get(ware.getId() + "_price"));
            amount.addAndGet(price.multiply(new BigDecimal(ware.getNum())).doubleValue());
        });
        log.error(String.valueOf(amount.get()));
        order.setAmount(BigDecimal.valueOf(amount.get()));
        order.setCreateDate(LocalDateTime.now());
        order.setUserId(Long.valueOf(StpUtil.getLoginId().toString()));
        //插入合并订单
        orderMapper.insert(order);
        //生成商品详细订单
        List<OrderDetail> orderList = list.stream().map(ware -> {
            BigDecimal price = BigDecimal.valueOf((Double) operations.get(ware.getId() + "_price"));
            OrderDetail orderDetail = new OrderDetail();
            orderDetail.setNum(ware.getNum());
            orderDetail.setWaresId(ware.getId());
            orderDetail.setCreateDate(LocalDateTime.now());
            orderDetail.setAmount(price.multiply(new BigDecimal(ware.getNum())));
            orderDetail.setUserId(Long.valueOf(StpUtil.getLoginId().toString()));
            orderDetail.setOrderId(order.getId());
            orderDetail.setCategoryId(wareMapper.selectOne(new LambdaQueryWrapper<Wares>().eq(Wares::getId, ware.getId())).getCategoryId());
            orderDetail.setMessage(ware.getDescription());
            Address address = addressMapper.selectOne(new LambdaQueryWrapper<Address>().eq(Address::getUserId, Long.valueOf(StpUtil.getLoginId().toString())).and(i -> i.eq(Address::getIsDefault, 1)));
            //地址为null则抛出自定义异常，下单失败
            if (ObjectUtils.isEmpty(address)) {
                throw new NoAddressException("没有设置收货地址!");
            }
            orderDetail.setReceiveAddress(address.getAddress());
            orderDetailMapper.insert(orderDetail);
            //构建需要传输的订单信息
            OrderDetail orderDetails = new OrderDetail();
            orderDetails.setOrderId(order.getId());
            orderDetails.setNum(ware.getNum());
            orderDetails.setWaresId(ware.getId());
            orderDetails.setUserId(orderDetail.getUserId());
            orderDetails.setId(orderDetail.getId());
//            operations.decrement(ware.getId() + "_num", ware.getNum());
            //获取当前商品库存
//            int wareNum = wareMapper.getWareNum(orderDetail.getWaresId());
//            //修改库存
//            wareMapper.updateWareNum(orderDetail.getWaresId(), wareNum - orderDetail.getNum());
            return orderDetails;
        }).collect(Collectors.toList());
//        //修改购物车里面的商品数量
//        shoppingCartService.updateShoppingCartWaresNum(Long.valueOf(StpUtil.getLoginId().toString()), orderList);

        //利用RabbitMQ异步发送订单
        rabbitTemplate.convertAndSend(Constant.ORDEREXCHANGE, Constant.ORDERKEY, ListByteConverterUtil.listToByteArray(orderList),
                //设置发送消息的延迟时间
                message -> {
                    message.getMessageProperties().setDelay(Constant.DelayTime);
                    return message;
                });
        log.error("订单发送个数:" + Constant.orderCount.incrementAndGet());
        //传递总订单号
        threadLocalUtils.set(order.getId());
        return aliPayUtil.pay(order.getId().toString(), order.getAmount().doubleValue(), "用户" + StpUtil.getLoginId() + "的订单");
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public R<String> secKillWareById(Long wareId) throws JsonProcessingException, AlipayApiException {
        //判断是否重复抢购
        if (redisTemplate.hasKey(StpUtil.getLoginId() + "-" + wareId)) {
            return R.error("一个用户一天只能抢购一次该商品!");
        }
        log.error(Constant.MEMORY_TAGS.get(wareId.toString()).toString());
        //内存标记，减少对redis的访问
        if (Constant.MEMORY_TAGS.get(wareId.toString())) {
            return R.error("该商品已经被抢购完!");
        }
        //库存预减
        redisTemplate.opsForValue().decrement(wareId + "_num");
        if ((Integer) redisTemplate.opsForValue().get(wareId.toString()) < 0) {
            Constant.MEMORY_TAGS.put(wareId.toString(), true);
            redisTemplate.opsForValue().increment(wareId + "_num");
            return R.error("商品已经被抢购完!");
        }
        //生成总订单
        Order order = new Order();
        order.setUserId(Long.valueOf(StpUtil.getLoginId().toString()));
        order.setCreateDate(LocalDateTime.now());
        order.setAmount(wareMapper.selectById(wareId).getPrice());
        orderService.save(order);


        //生成订单
        OrderDetail orderDetail = new OrderDetail();
        orderDetail.setUserId(Long.valueOf(StpUtil.getLoginId().toString()));
        orderDetail.setWaresId(wareId);
        orderDetail.setCreateDate(LocalDateTime.now());
        orderDetail.setNum(1);
        BigDecimal price = new BigDecimal(redisTemplate.opsForValue().get(wareId + "_price").toString());
        orderDetail.setAmount(price.multiply(new BigDecimal(1)));
        orderDetail.setOrderId(order.getId());
        orderDetail.setMessage("秒杀活动商品");
        orderDetail.setCategoryId(wareMapper.selectOne(new LambdaQueryWrapper<Wares>().eq(Wares::getId, wareId)).getCategoryId());
        ArrayList<OrderDetail> orderDetails = new ArrayList<>();
        orderDetails.add(orderDetail);
        //利用RabbitMQ异步发送订单
        ObjectMapper mapper = new ObjectMapper();
        mapper.registerModule(new JavaTimeModule());
        rabbitTemplate.convertAndSend(Constant.ORDEREXCHANGE, Constant.ORDERKEY, mapper.writeValueAsBytes(orderDetails),
                //设置发送消息的延迟时间
                message -> {
                    message.getMessageProperties().setDelay(Constant.DelayTime);
                    return message;
                });
        log.info("订单发送成功!");
        redisTemplate.opsForValue().set(StpUtil.getLoginId() + "-" + wareId, true, 24, TimeUnit.HOURS);

        return R.success(aliPayUtil.pay(order.getId().toString(), order.getAmount().doubleValue(), orderDetail.getMessage() + "付款"));
    }

    @Override
    public Long getWareIdByName(String name) {
        return wareMapper.getWareIdByName(name);

    }

}
